package com.fsh.lingsp.common.chat.controller;


import com.fsh.lingsp.common.chat.domain.dto.MsgReadInfoDTO;
import com.fsh.lingsp.common.chat.domain.vo.request.*;
import com.fsh.lingsp.common.chat.domain.vo.response.ChatMessageReadResp;
import com.fsh.lingsp.common.chat.domain.vo.response.ChatMessageResp;
import com.fsh.lingsp.common.chat.service.ChatService;
import com.fsh.lingsp.common.common.annotation.FrequencyControl;
import com.fsh.lingsp.common.common.domain.vo.resp.ApiResult;
import com.fsh.lingsp.common.common.domain.vo.resp.CursorPageBaseResp;
import com.fsh.lingsp.common.common.utils.RequestHolder;
import com.fsh.lingsp.common.user.domain.enums.BlackTypeEnum;
import com.fsh.lingsp.common.user.service.cache.UserCache;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * 作者：fsh
 * 日期：2024/03/10
 *
 * 群聊相关接口
 */
@RestController
@RequestMapping("/capi/chat")
@Api(tags = "聊天室相关接口")
@Slf4j
public class ChatController {
    @Autowired
    private ChatService chatService;
    @Autowired
    private UserCache userCache;



    /**
     * 游标翻页
     * 获取消息列表。一般是往上翻记录。
     * @param request 请求， 里面包含的是房间id。  翻得是哪一个房间
     */
    @GetMapping("/public/msg/page")
    @ApiOperation("消息列表")
    @FrequencyControl(time = 120, count = 20, target = FrequencyControl.Target.IP)
    public ApiResult<CursorPageBaseResp<ChatMessageResp>> getMsgPage(@Valid ChatMessagePageReq request) {
        CursorPageBaseResp<ChatMessageResp> msgPage = chatService.getMsgPage(request, RequestHolder.get().getUid());
        //调用黑名单过滤的方法。 避免消息更新的不及时
        filterBlackMsg(msgPage);
        return ApiResult.success(msgPage);
    }

    /**
     * 黑名单过滤
     */
    private void filterBlackMsg(CursorPageBaseResp<ChatMessageResp> memberPage) {
        Set<String> blackMembers = getBlackUidSet();
        //如果消息列表中有 黑名单发言 ，则移除掉。
        memberPage.getList().removeIf(a -> blackMembers.contains(a.getFromUser().getUid().toString()));
    }

    /**
     * 咖啡因中获取黑名单缓存 ，获取被拉黑的 uid  集合
     */
    private Set<String> getBlackUidSet() {
        return userCache.getBlackMap().getOrDefault(BlackTypeEnum.UID.getType(), new HashSet<>());
    }

    /**
     * 当前用户发送消息
     * @see com.fsh.lingsp.common.chat.domain.enums.MessageTypeEnum
     */
    @PostMapping("/msg")
    @ApiOperation("发送消息")
    @FrequencyControl(time = 5, count = 3, target = FrequencyControl.Target.UID)
    @FrequencyControl(time = 30, count = 5, target = FrequencyControl.Target.UID)
    @FrequencyControl(time = 60, count = 10, target = FrequencyControl.Target.UID)
    public ApiResult<ChatMessageResp> sendMsg(@Valid @RequestBody ChatMessageReq request) {
        Long msgId = chatService.sendMsg(request, RequestHolder.get().getUid());
        //返回完整消息格式，方便前端展示
        return ApiResult.success(chatService.getMsgResp(msgId, RequestHolder.get().getUid()));
    }

    /**
     * 消息标记。 （点赞点踩）
     *
     * @param request 请求
     */
    @PutMapping("/msg/mark")
    @ApiOperation("消息标记")
//    @FrequencyControl(time = 10, count = 5, target = FrequencyControl.Target.UID)
    public ApiResult<Void> setMsgMark(@Valid @RequestBody ChatMessageMarkReq request) {
        chatService.setMsgMark(RequestHolder.get().getUid(), request);
        return ApiResult.success();
    }

    /**
     * 撤回消息
     * @param request 里面包括了 消息id 和 房间id
     */
    @PutMapping("/msg/recall")
    @ApiOperation("撤回消息")
//    @FrequencyControl(time = 20, count = 3, target = FrequencyControl.Target.UID)
    public ApiResult<Void> recallMsg(@Valid @RequestBody ChatMessageBaseReq request) {
        chatService.recallMsg(RequestHolder.get().getUid(), request);
        return ApiResult.success();
    }

    /**
     * 消息的已读未读列表。 已读和未读都会请求一次这个接口。
     *
     * @param request 请求
     * @return ChatMessageReadResp 已读或者未读的用户uid集合的游标翻页
     * 前端会拿着uid ，去浏览器缓存中找到用户的信息。
     */
    @GetMapping("/msg/read/page")
    @ApiOperation("消息的已读未读列表")
    public ApiResult<CursorPageBaseResp<ChatMessageReadResp>> getReadPage(@Valid ChatMessageReadReq request) {
        Long uid = RequestHolder.get().getUid();
        return ApiResult.success(chatService.getReadPage(uid, request));
    }

    /**
     * 获取消息的已读未读总数
     *
     * @param request 请求 （本人的消息id集合）
     *                这个消息id集合 仅仅只是当前房间能看到的“我”发的消息。
     *                具体由 前端决定传递。
     */
    @GetMapping("/msg/read")
    @ApiOperation("获取消息的已读未读总数")
    public ApiResult<Collection<MsgReadInfoDTO>> getReadInfo(@Valid ChatMessageReadInfoReq request) {
        Long uid = RequestHolder.get().getUid();
        return ApiResult.success(chatService.getMsgReadInfo(uid, request));
    }

    /**
     * 用户房间消息阅读时间上报入库
     *
     * @param request 请求 （里面只包含一个 房间id）
     * @return {@link ApiResult }<{@link Void }>
     */
    @PutMapping("/msg/read")
    @ApiOperation("用户房间消息阅读时间上报入库")
    public ApiResult<Void> msgRead(@Valid @RequestBody ChatMessageMemberReq request) {
        Long uid = RequestHolder.get().getUid();
        chatService.msgRead(uid, request);
        return ApiResult.success();
    }
}

